import Map from "ol/Map.js";
import View from "ol/View.js";

import { defaults } from "ol/control"

import { Tile as TileLayer, Vector as VectorLayer, Heatmap as HeatmapLayer } from 'ol/layer.js';
// import {Heatmap as HeatmapLayer, Tile as TileLayer} from 'ol/layer';
import { XYZ, TileWMS, Vector as VectorSource, Cluster } from 'ol/source.js';
import { Circle as CircleStyle, Fill, Stroke, Style, Text, Icon } from 'ol/style.js';
import { Point, LineString } from "ol/geom"
import Feature from "ol/Feature"
import zMapLayer from "./zMapLayer"
import Overlay from 'ol/Overlay.js';
import { getCenter } from 'ol/extent';
import GeoJSON from "ol/format/GeoJSON"
/**
 * 说明：创建地图对象类
 */
class ZMap extends zMapLayer {
    constructor(option) {
        super()
        this.fillStyle = new Fill({
            color: 'rgba(255, 255, 255, 0.8)'
        })
        // 边界样式
        this.strokeStyle = new Stroke({
            color: '#ffcc33',
            width: 2
        })
        // 形状原型样式
        this.imageCircle = new CircleStyle({
            radius: 17,
            fill: new Fill({
                color: '#ffcc33'
            })
        })
        this.icon_style = {
            anchor: [0.5, 1],
            offset: [0, 1],
            //图标缩放比例
            scale: 0.8,
            //透明度
            opacity: 1,
            //图标的url
            src: "../skins/default/images/StationImages/yc_pp.png" //注意这里使用绝对路径传参
        }
        this.style = new Style({
            //填充色
            fill: this.fillStyle,
            //边线颜色
            stroke: this.strokeStyle,
            //形状
            image: this.imageCircle
        })

        if (!option)
            return
        var target = option.target ? option.target : 'map'
        var zoom = option.zoom ? option.zoom : this.zoom
        var center = option.center ? option.center : this.center
        var olMap = new Map({
            target: target,
            view: new View({
                projection: 'EPSG:4326',
                center: center,
                zoom: zoom
            }),
            controls: defaults({
                zoom: false,
                rotate: false,
                attribution: false
            })
        });
        this.map = olMap
        /**
        *鼠标移动到要素上面的时候变成小手
        */
        olMap.on('pointermove', function (e) {
            var pixel = olMap.getEventPixel(e.originalEvent);
            var hit = olMap.hasFeatureAtPixel(pixel);
            olMap.getTargetElement().style.cursor = hit ? 'pointer' : '';
        });

        // if(baseMap)
        //     var vetorLayers = this.tiandituVetorMap(olMap)
        // return olMap
    }
    /**
     * 说明：添加点
     * @param {*} option 参数
     * points：对象，坐标点，
     * {
     *      center:坐标信息,
            imgUrl:图标地址,
            title：标注文本信息标题头,
            element：自定义提示框写html
     * }
     * layerId：图层名称
     * label： 布尔值，是否显示标注文本信息
     * name：显示内容的名称
     * key:是每一个点含有的一个数值key值
     * divPop:全自定pop,不使用模板
     * 示例：
     * {
            points: [{
                center: [114.6727, 35.5028],
                imgUrl:"images/StationImages/maker/压力计.png",
                name:"水质",
                title:"123",
                element:"<div>3333333</div>"
            }],
            layerId:"222",
            label:true,
            name:"提示",
            key:"name",
        }
     */
    addPoint(option) {
        var that = this
        if (option.points && option.points.length < 1)
            return false
        let overlayes = []
        //创建一个点
        let points = []

        option.points.map(function (item, index) {
            let point_ = new Feature({
                geometry: new Point(item.center),
            });
            point_.data = item;
            point_.layerId = option.layerId ? option.layerId : ""

            let style_ = new Style({
                //形状
                image: new Icon({
                    offset: [0, 1],
                    //图标缩放比例
                    scale: item.scale ? item.scale : 0.8,
                    //透明度
                    opacity: 1,
                    //图标的url
                    src: item.imgUrl ? item.imgUrl : "images/StationImages/marker.png" //注意这里使用绝对路径传参
                })
            })
            //设置点1的样式信息
            point_.setStyle(style_);
            points.push(point_)

            // 显示标签
            if (option.label) {
                var point_div = document.createElement('div');

                if (option.divPop) {
                    if (item.element) {
                        point_div.innerHTML = item.element
                    } else {
                        if (option.name) {
                            point_div.innerHTML = `<div class="point-info-header">${option.name}：${option.key ? item[option.key] : ""}</div>`
                        } else {
                            point_div.innerHTML = `<div class="point-info-header">${option.key ? item[option.key] : ""}</div>`
                        }
                    }
                } else {
                    let html = `<div class="point-info-box">`
                    // 默认标签样式
                    if (item.element) {
                        html += `<div class="point-info-header">${item.title ? item.title : "信息"}</div>
                                <div class="point-info-content">${item.element ? item.element : ""}</div>`
                    } else {
                        html += ` <div class="point-info-header">${item.title ? item.title : "信息"}</div>`
                        if (option.name) {
                            html += `<div class="point-info-content">${option.name}：${option.key ? item[option.key] : ""}</div>`
                        } else {
                            html += `<div class="point-info-content">${option.key ? item[option.key] : ""}</div>`
                        }
                    }
                    html += `</div>`
                    point_div.innerHTML = html
                }

                let pointOver = new Overlay({
                    position: item.center,//默认空
                    positioning: 'center-bottom',
                    element: point_div,//绑定上面添加的元素
                    offset: [0, 10]//图片偏移量
                });
                that.map.addOverlay(pointOver);
                overlayes.push(pointOver)
            }
        })
        //实例化一个矢量图层Vector作为绘制层
        var source = new VectorSource({
            features: points
        });
        //创建一个图层
        var vector = new VectorLayer({
            source: source
        });
        vector.layerId = option.layerId
        //将绘制层添加到地图容器中
        this.map.addLayer(vector);
        vector.setZIndex(3);
        return {
            layer: vector,
            overLayer: overlayes
        };
    }
    /**
    * 说明：添加线段
    * @param {*} option 参数
    * points：对象，坐标点，
    *  [
       [114.44351865955855, 35.25606324971926, 0],
       [114.4439913702056, 35.258289919844, 0],
     ]
    * layerId：图层名称
    * label： 布尔值，是否显示标注文本信息
    * name：显示内容的名称
    * key:是每一个点含有的一个数值key值
    * divPop:全自定pop,不使用模板
    * 示例：
    * {
           points: [
            [114.44351865955855, 35.25606324971926, 0],
            [114.4439913702056, 35.258289919844, 0],
     ];,
           layerId:"222",
           label:true,
           name:"性别",
           key:"name",
       }
    */
    addLineString(option) {
        var that = this
        if (option.points && option.points.length < 1)
            return false
        //创建一个点数组
        let points = []

        option.points.map(function (item, index) {
            points.push(new Point(item),);
        });
        var featureLine = new Feature({
            geometry: new LineString(option.points)
        });
        var vSource = new VectorSource()
        var vLayer = new VectorLayer(
            {
                source: vSource,
            }
        )
        var street = featureLine;
        this.map.addLayer(vLayer);


        var textStyle = new Style({
            text: new Text({
                font: 'bold 26px Mirosoft Yahei',
                placement: 'line',
                text: "动态路径",
                fill: new Fill({
                    color: '#000'
                }),
                offsetY: 3,
                stroke: new Stroke({
                    color: '#FFF',
                    width: 2
                })
            })
        })
        var buttomPathStyle = new Style({
            stroke: new Stroke({
                color: [4, 110, 74],
                width: 28
            }),
        })
        var upperPathStyle = new Style({

            stroke: new Stroke({
                color: [0, 186, 107],
                width: 20
            }),
        })
        var outStyle = new Style({
            image: new CircleStyle({
                radius: 18,
                fill: new Fill({
                    color: [4, 110, 74]
                })
            })
        })
        var midStyle = new Style({
            image: new CircleStyle({
                radius: 15,
                fill: new Fill({
                    color: [0, 186, 107]
                })
            })
        })
        var innerDot = new Style({
            image: new CircleStyle({
                radius: 6,
                fill: new Fill({
                    color: [255, 255, 255]
                })
            })
        })
        var foutrStyle = new Style({
            image: new CircleStyle({
                radius: 18,
                fill: new Fill({
                    color: "#000"
                })
            })
        })
        var fmidStyle = new Style({
            image: new CircleStyle({
                radius: 15,
                fill: new Fill({
                    color: '#FFF'
                })
            })
        })
        var finnerStyle = new Style({
            image: new CircleStyle({
                radius: 6,
                fill: new Fill({
                    color: '#000'
                })
            })
        })
        street.setStyle(textStyle);
        vSource.addFeature(street);



        var offset = 0.01;
        this.map.on('postcompose', (evt) => {
            var vct = evt.vectorContext;
            vct.drawFeature(street, buttomPathStyle)
            vct.drawFeature(street, upperPathStyle)
            let numArr = Math.ceil((street.getGeometry().getLength() / this.map.getView().getResolution()) / 100)
            var points = []
            for (var i = 0; i <= numArr; i++) {
                let fracPos = (i / numArr) + offset;
                if (fracPos > 1) fracPos -= 1
                let pf = new Feature(new Point(street.getGeometry().getCoordinateAt(fracPos)));
                points.push(pf);
            }

            //确定方向并绘制
            street.getGeometry().forEachSegment((start, end) => {
                points.forEach((item) => {
                    let line = new LineString([start, end])
                    let coord = item.getGeometry().getFirstCoordinate();
                    let cPoint = line.getClosestPoint(coord);
                    if (Math.abs(cPoint[0] - coord[0]) < 1 && Math.abs(cPoint[1] - coord[1]) < 1) {
                        var myImage = new Image(117, 71);
                        myImage.src = "images/StationImages/arrow1.png";
                        let dx = end[0] - start[0];
                        let dy = end[1] - start[1];
                        var rotation = Math.atan(dx / dy);
                        rotation = dy > 0 ? rotation : (Math.PI + rotation);
                        vct.setStyle(new Style({
                            image: new Icon({
                                img: myImage,
                                imgSize: [117, 71],
                                scale: 0.15,
                                rotation: rotation
                            })
                        }))
                        vct.drawGeometry(item.getGeometry())
                    }
                });
                vct.setStyle(outStyle)
                vct.drawGeometry(new Point(street.getGeometry().getFirstCoordinate()))
                vct.setStyle(midStyle)
                vct.drawGeometry(new Point(street.getGeometry().getFirstCoordinate()))
                vct.setStyle(innerDot)
                vct.drawGeometry(new Point(street.getGeometry().getFirstCoordinate()));
                vct.setStyle(foutrStyle)
                vct.drawGeometry(new Point(street.getGeometry().getLastCoordinate()))
                vct.setStyle(fmidStyle)
                vct.drawGeometry(new Point(street.getGeometry().getLastCoordinate()))
                vct.setStyle(finnerStyle)
                vct.drawGeometry(new Point(street.getGeometry().getLastCoordinate()));
            })

            offset = offset + 0.003
            //复位
            if (offset >= 1) offset = 0.001
            this.map.render()
        });


        return vLayer;

    }

    selectByAttribute(layer, key, value) {
        var features = layer.layer.getSource().getFeatures();

        var selectedByAttriFeature = [];//实际应用中设置成全局变量
        for (var i = 0, ii = features.length; i < ii; i++) {
            if (features[i].get(key) == value) {
                selectedByAttriFeature.push(features[i]);
            }
        } if (selectedByAttriFeature.length == 0) { return null }
        else { return selectedByAttriFeature; }

    }
    goTo(feature) {
        // var my_view = new View({
        //     center: this.getCenterOfExtent(feature.getGeometry().getExtent()),
        //     zoom: this.map.getView().getZoom(),
        // });
        // this.map.setView(my_view);
        //this.map.getView().setCenter(this.getCenterOfExtent(feature.getGeometry().getExtent()));
        this.map.getView().setCenter(getCenter(feature.getGeometry().getExtent()));
        this.map.getView().setZoom(12);
    }
    /**
    * 通过id获得图层
    * @param {*} layer 
    * layer 定义layerId 属性
    */
    getLayerByID(id) {
        let layer;
        this.map.getLayers().forEach(function (lyr) {
            if (id === lyr.layerId || id === lyr.layerID) {
                layer = lyr;
            }
        });
        return layer;
    }
    /**
     * 移除添加的点图层
     * @param {*} layer 
     */
    removeLayer(layer) {
        if (layer && layer.layer) {
            this.map.removeLayer(layer.layer)
        }
        if (layer && layer.overLayer) {
            layer.overLayer.map((item, index) => {
                this.map.removeOverlay(item)
            })
        }
    }
    /**
     * 添加闪烁标注信息
     * @param {*} option 
     */
    addAnimatePoint(option) {
        let makers = []

        if (option.points && option.points.length > 0) {
            option.points.map((item, index) => {
                // 定义默认的图标
                let icon = "iconjingbaoxinxi-"
                var point_div = document.createElement('div');
                if (item.icon)
                    icon = item.icon
                let html = `<div class="commodity-sign-wrap" style="cursor: pointer;">
                                    <div class="circle"><i class="iconfont ${icon} "></i></div>
                                    <div class="circle_bottom animation "></div>
                                    <div class="circle_bottom2 animation2 "></div>
                            </div>  `
                point_div.innerHTML = html
                // 创建图层
                let point = new Overlay({
                    position: item.center ? item.center : [0, 0],//默认空
                    positioning: 'center-bottom',
                    element: point_div,//绑定上面添加的元素
                    offset: [0, 0]//图片偏移量
                });
                // 和地图关联
                this.map.addOverlay(point);
                makers.push(point)

                // 绑定点击事件
                point_div.onclick = function () {
                    if (option.click) option.click(item)
                }
            })
        }
        return {
            overLayer: makers
        }
    }
    /**
     * 重置地图
     * @param {*} map 
     * @param {*} params 
     */
    restMap(params) {
        let view = this.map.getView()
        if (params && params.center)
            view.setCenter(params.center)
        if (params && params.zoom)
            view.setZoom(params.zoom)
    }
    /**
     * 说明：根据数据生产热力图，目前支持两种方式渲染数据
     * url: 1、根据geojson的url地址进行数据的渲染
     * points: 2、根据后台返回的点位数据进行渲染，points是数组，里边是每一个点的信息，
     *  格式如下 points:[{
     *              center:[113.4,34.2]
     *          },{
     *              center:[113.4,34.2]
     *          }]
     * 3、weight 是一个自定义渲染的函数，用户可以根据自己的字段进行数据的渲染
     * 备注：两种渲染模型根据实际情况调用，只需要调用其中之一即可
     * @param {*} option 
     */
    showHeatMap(option) {
        let source = null
        // 通过geojson的url地址进行解析数据
        if (option && option.url)
            source = new VectorSource({
                url: option.url,
                format: new GeoJSON()
            })
        // 根据点位信息进行渲染成热力图
        if (option && option.points && option.points.length > 0) {
            let points = []
            option.points.map((item, index) => {
                let point_ = new Feature({
                    geometry: new Point(item.center),
                });
                point_.data = item;
                points.push(point_)
            })
            source = new VectorSource({
                features: points
            })
        }
        if (!source)
            throw new Error("url和points参数无效");

        let data = {
            source: source,
            blur: 15,
            radius: 15,
        }
        // 标记，需要进一步判断遍历是否是函数
        if (option.weight && typeof option.weight === "function")
            data.weight = function (feature) {
                return option.weight(feature);
            }
        let vector = new HeatmapLayer(data)
        this.map.addLayer(vector)
        return {
            layer: vector,
        };
    }

    /**
     * 说明：保存地图为png图
     * @param {*} name    选填，字符串，默认导出是map.png
     */
    saveMapPng(name = "map") {
        // 实现canvas转化成图片
        this.map.once('postcompose', function (event) {
            var canvas = event.context.canvas;
            var MIME_TYPE = "image/png";

            var imgURL = canvas.toDataURL(MIME_TYPE);
            console.log(imgURL)
            var dlLink = document.createElement('a');
            dlLink.download = name + ".png";
            dlLink.href = imgURL;
            dlLink.dataset.downloadurl = [MIME_TYPE, dlLink.download, dlLink.href].join(':');

            document.body.appendChild(dlLink);
            dlLink.click();
            document.body.removeChild(dlLink);
        });
        map.renderSync();
    }
}

export default ZMap



